#ifndef RTPPARSE_RECEIVERREPORT_H
#define RTPPARSE_RECEIVERREPORT_H

#include "rtp/Packet.h"
#include "utils.h"

/**
 * RR的核心功能
 * 1.丢包率计算
 * 2.抖动计算
 * 3.RTT计算(关键功能)
 *  接收端通过RR中的LSR和DLSR字段使发送端能够计算往返时间
 *   根据丢包率调整码率
 * 
 * RR的实际作用：
 *  1.网络质量监控
 *      基于RR指标的网络质量评估， 根据丢包率评估   根据抖动评估
 *  2.拥塞控制
 *      根据丢包率和RTT调整
 * 
 *  3.媒体同步
 *      使用RR中的抖动信息调整播放缓冲区
 *      基础缓冲200ms    抖动缓冲    丢包补偿
 * 
 * RR的发送规则
 *  根据RFC3550 RR的发送间隔应遵循复合RTCP包的发送规则:
 * 带宽分配
 *  在典型的WebRTC会话中:
 *      RTCP占用总带宽的5%
 *      RR通常占用RTCP带宽的75%
 *      剩余带宽用于SR,SDES等其它RTCP包
 * 
 * 网络问题诊断:
 *  1.丢包模式分析
 *     # 持续高丢包率  -> 网络拥塞
 *     # 间歇性丢包 -> 无线网络问题
 *     # 突发性丢包 -> 路由变化或缓冲溢出
 *  2.抖动分析:
 *      # 低抖动  --> 稳定网络
 *      # 高抖动  --> 网络拥堵或路由不稳定
 *      # 抖动突变 --> 网络路径变化
 *  3.RTT分析:
 *      # 低RTT -> 本地网络或近距离
 *      # 高RTT -> 远距离
 *      # RTT波动   -> 网络拥堵或路由变化
 */
namespace Rtp {
    namespace Rtcp {
        // 报告块字段
        class ReceiverReport {
        public:
            struct Header {
                uint32_t ssrc;
                uint32_t fractionLost: 8; // 自上次RR以来丢失的包比例
                uint32_t totalLost: 24; // 累计丢失的包总数
                uint32_t lastSeq; // 接收到的最高序列号(处理回绕)
                uint32_t jitter; // 包到达时间间隔的抖动估计
                uint32_t lsr; // 最后收到的SR的NTP时间戳中间32位
                uint32_t dlsr; // 自收到最后一个SR以来的延迟
            };
        public:
            static const size_t HeaderSize { 24 };
            static ReceiverReport* Parse(const uint8_t*data, size_t len);
        public:
            ReceiverReport() {
                this->header = reinterpret_cast<Header *>(this->raw);
            }
            explicit ReceiverReport(Header *header): header(header) {}
            explicit ReceiverReport(ReceiverReport *report): header(report->header) {}

        public:
            void Dump() const;
            size_t Serialize(uint8_t *buffer);
            size_t GetSize() const {
                return HeaderSize;
            }

            uint32_t GetSsrc() const {
                return uint32_t{ ntohl(this->header->ssrc) };
            }

            void SetSsrc(uint32_t ssrc) {
                this->header->ssrc = uint32_t{ htonl(ssrc) };
            }

            uint8_t GetFractionLost() const {
                return uint8_t{ Utils::Byte::Get1Byte((uint8_t*)this->header, 4) };
            }

            void SetFractionLost(uint8_t fractionLost) {
                Utils::Byte::Set1Byte((uint8_t*)this->header, 4, fractionLost);
            }

            int32_t GetTotalLost() const {
                auto value = uint32_t{ Utils::Byte::Get3Bytes((uint8_t *)this->header, 5) };

                if (((value >> 23) & 1) == 0) {
                    return value;
                }
                
                if (value != 0x0800000) {
                    value &= ~(1 << 23);
                }
                return -value;
            }

            void SetTotalLost(int32_t totalLost) {
                int32_t clamp = (totalLost >= 0) ? totalLost > 0x07FFFFF ? 0x07FFFFF : totalLost : -totalLost > 0x0800000 ? 0x0800000 : -totalLost;
                uint32_t value = (totalLost >= 0) ? (clamp & 0x07FFFFF) : (clamp | 0x0800000);

                Utils::Byte::Set3Bytes(reinterpret_cast<uint8_t *>(this->header), 5, value);
            }

            uint32_t GetLastSeq() const {
                return uint32_t{ ntohl(this->header->lastSeq) };
            }

            void SetLastSeq(uint32_t lastSeq) const {
                this->header->lastSeq = uint32_t{ htonl(lastSeq) };
            }

            uint32_t GetJitter() const {
                return uint32_t{ ntohl(this->header->jitter) };
            }

            void SetJitter(float jitter) const {
                this->header->jitter = uint32_t{ htonl(static_cast<uint32_t>(jitter))};
            }

            uint32_t GetLastSenderReport() const {
                return uint32_t{ ntohl(this->header->lsr) };
            }

            void SetLastSenderReport(uint32_t lsr) {
                this->header->lsr = uint32_t { htonl(lsr) };
            }

            uint32_t GetDelaySinceLastSenderReport() const {
                return uint32_t{ ntohl(this->header->dlsr) };
            }

            void SetDelaySinceLastSenderReport(uint32_t dlsr) {
                this->header->dlsr = uint32_t{ htonl(dlsr) };
            }
        private:
            Header *header { nullptr };
            uint8_t raw[HeaderSize] { 0u };
        };

        class ReceiverReportPacket: public Packet {
        public:
            static size_t MaxReportsPerPacket;
            using Iterator = std::vector<ReceiverReport *>::iterator;

        public:
            static ReceiverReportPacket* Parse(const uint8_t* data, size_t len, size_t offset = 0);
        public:
            ReceiverReportPacket(): Packet(Type::RR) {}

            explicit ReceiverReportPacket(CommonHeader* commonHeader): Packet(commonHeader) {}

            ~ReceiverReportPacket() override {
                for (auto *report : this->reports) {
                    delete report;
                }
            }

            uint32_t GetSsrc() const {
                return this->ssrc;
            }

            void SetSsrc(uint32_t ssrc) {
                this->ssrc = ssrc;
            }

            void AddReport(ReceiverReport* report) {
                this->reports.push_back(report);
            }

            void RemoveReport(ReceiverReport *report) {
                auto it = std::find(this->reports.begin(), this->reports.end(), report);
                if (it != this->reports.end()) {
                    this->reports.erase(it);
                }
            }

            Iterator Begin() {
                return this->reports.begin();
            }

            Iterator End() {
                return this->reports.end();
            }

        public:
            void Dump() const override;

            size_t Serialize(uint8_t* buffer) const override;
            Type GetType() const override {
                return Type::RR;
            }

            size_t GetCount() const override {
                return this->reports.size();
            }

            size_t GetSize() const override {
                size_t size = (Packet::CommonHeaderSize + 4u) * ((this->GetCount() / MaxReportsPerPacket) + 1);

                size += ReceiverReport::HeaderSize * this->GetCount();

                return size;
            }
        private:
            uint32_t ssrc{ 0u };
            std::vector<ReceiverReport *> reports;
        };
    }
}

#endif